﻿using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Repid.Redis
{
    /// <summary>
    /// 公用存储类
    /// </summary>
    public static class CommonRedis
    {
        // Install-Package ServiceStack -Version 3.9.71

        /// <summary>
        /// 默认超时时间（分钟）
        /// </summary>
        private const double TIMEOUT = 20;

        /// <summary>
        /// 存储客户端
        /// </summary>
        private static RedisClient NewClient
        {
            get { return new RedisClient("127.0.0.1", 6379); }
        }

        /// <summary>
        /// 键是否存在
        /// </summary>
        /// <param name="client">客户端</param>
        /// <param name="key">存储键</param>
        /// <returns>键内容数量</returns>
        private static long ExistsKey(RedisClient client, string key)
        {
            return client.Exists(key);
        }

        /// <summary>
        /// 写入内容
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="client">客户端</param>
        /// <param name="key">存储键</param>
        /// <param name="obj">存储值</param>
        /// <param name="minutes">超时时间</param>
        /// <returns>是否成功</returns>
        private static bool SetValue<T>(RedisClient client, string key, T obj, double minutes = TIMEOUT) where T : class
        {
            return client.Set<T>(key, obj, DateTime.Now.AddMinutes(minutes));
        }

        /// <summary>
        /// 读取内容
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="client">客户端</param>
        /// <param name="key">存储键</param>
        /// <param name="minutes">超时时间</param>
        /// <returns>内容</returns>
        private static T GetValue<T>(RedisClient client, string key, double minutes = TIMEOUT) where T : class
        {
            if (ExistsKey(client, key) < 1)
            {
                return null;
            }
            if (client.Ttl(key) < (TIMEOUT / 2) * 60)
            {
                client.ExpireEntryAt(key, DateTime.Now.AddMinutes(minutes));
            }
            return client.Get<T>(key);
        }

        /// <summary>
        /// 键是否存在
        /// </summary>
        /// <param name="key">存储键</param>
        /// <returns>键内容数量</returns>
        public static long ExistsKey(string key)
        {
            using (var client = NewClient)
            {
                return ExistsKey(client, key);
            }
        }

        /// <summary>
        /// 移除键
        /// </summary>
        /// <param name="key">存储键</param>
        /// <returns>是否成功</returns>
        public static bool RemoveKey(string key)
        {
            using (var client = NewClient)
            {
                if (ExistsKey(client, key) < 1)
                {
                    return false;
                }
                return client.Remove(key);
            }
        }

        /// <summary>
        /// 写入内容
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="key">存储键</param>
        /// <param name="obj">存储值</param>
        /// <param name="minutes">超时时间</param>
        /// <returns>是否成功</returns>
        public static bool SetValue<T>(string key, T obj, double minutes = TIMEOUT) where T : class
        {
            using (var client = NewClient)
            {
                return SetValue<T>(client, key, obj, minutes);
            }
        }

        /// <summary>
        /// 读取内容
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="key">存储键</param>
        /// <param name="minutes">超时时间</param>
        /// <returns>内容</returns>
        public static T GetValue<T>(string key, double minutes = TIMEOUT) where T : class
        {
            using (var client = NewClient)
            {
                if (ExistsKey(client, key) < 1)
                {
                    return null;
                }
                return GetValue<T>(client, key, minutes);
            }
        }

        /// <summary>
        /// 读取内容
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="key">存储键</param>
        /// <param name="func">存储值委托</param>
        /// <param name="minutes">超时时间</param>
        /// <returns>内容</returns>
        public static T GetValue<T>(string key, Func<T> func, double minutes = TIMEOUT) where T : class
        {
            using (var client = NewClient)
            {
                if (ExistsKey(client, key) < 1)
                {
                    T obj = null;

                    if (func != null)
                    {
                        obj = func();

                        if (obj != null)
                        {
                            SetValue<T>(client, key, obj, minutes);
                        }
                    }

                    return obj;
                }
                else { return GetValue<T>(client, key, minutes); };
            }
        }
    }
}